package com.zhuanzhuan.hero.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuanzhuan.hero.user.entity.HeroUserLabelAuthRecord;
import com.zhuanzhuan.hero.user.enums.LabelAuthOperateTypeEnum;
import com.zhuanzhuan.hero.user.enums.LabelTypeEnum;
import com.zhuanzhuan.hero.user.enums.StateEnum;
import com.zhuanzhuan.hero.user.mapper.HeroUserLabelAuthRecordMapper;
import com.zhuanzhuan.hero.user.pojo.bo.AuthDateNumBO;
import com.zhuanzhuan.hero.user.pojo.bo.CreateAuthRecordBO;
import com.zhuanzhuan.hero.user.service.HeroUserLabelAuthRecordService;
import com.zhuanzhuan.hero.user.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * dal Interface:HeroUserLabelAuthRecord
 * @author hanjunjun
 * @date 2024-7-3
 */
@Service
@Slf4j
public class HeroUserLabelAuthRecordServiceImpl extends ServiceImpl<HeroUserLabelAuthRecordMapper, HeroUserLabelAuthRecord>
    implements HeroUserLabelAuthRecordService {

    @Override
    public List<HeroUserLabelAuthRecord> queryAuthRecord(Long fromUid, Long toUid, Integer labelType,
        Integer operateType) {
        HeroUserLabelAuthRecord query = new HeroUserLabelAuthRecord();
        query.setFromUid(fromUid);
        query.setToUid(toUid);
        query.setLabelType(labelType);
        query.setOperateType(operateType);
        query.setState(StateEnum.EFFECTIVE.getCode());

        return getBaseMapper().select(query);
    }

    @Override
    public void delById(Long id) {
        LambdaUpdateWrapper<HeroUserLabelAuthRecord> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelAuthRecord::getState, StateEnum.IS_DELETED.getCode())
            .eq(HeroUserLabelAuthRecord::getId, id);
        this.update(updateWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createAuthRecord(CreateAuthRecordBO createAuthRecordBO) {
        //进行认证的时候把其他取消认证的记录删掉，否则认证-取消-认证-取消  第二次取消会校验幂等而操作失败
        this.delAuthRecord(createAuthRecordBO.getFromUid(), createAuthRecordBO.getToUid(), createAuthRecordBO.getLabelType(),
            LabelAuthOperateTypeEnum.CANCEL_AUTH.getCode());

        //插入新记录
        createAuthRecordBO.setOperateType(LabelAuthOperateTypeEnum.AUTH.getCode());
        this.save(this.buildEntity(createAuthRecordBO));
    }

    @Override
    public void createCancelAuthRecord(CreateAuthRecordBO createAuthRecordBO) {
        //用户近期动态统计逻辑：3天前认证了一次，2天前认证了一次，今天取消认证，视作3天内没有认证  所以这儿取消认证的时候把成功认证的记录删除
        if (LabelTypeEnum.FRATERNITY_AUTH.getCode().equals(createAuthRecordBO.getLabelType())) {
            this.delAuthRecord(createAuthRecordBO.getFromUid(), createAuthRecordBO.getToUid(), createAuthRecordBO.getLabelType(),
                LabelAuthOperateTypeEnum.AUTH.getCode());
        }

        //插入新记录
        createAuthRecordBO.setOperateType(LabelAuthOperateTypeEnum.CANCEL_AUTH.getCode());
        this.save(this.buildEntity(createAuthRecordBO));
    }

    @Override
    public void delAuthRecord(Long fromUid, Long toUid, Integer labelType, Integer operateType) {
        LambdaUpdateWrapper<HeroUserLabelAuthRecord> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelAuthRecord::getState, StateEnum.IS_DELETED.getCode())
            .eq(HeroUserLabelAuthRecord::getFromUid, fromUid)
            .eq(HeroUserLabelAuthRecord::getToUid, toUid)
            .eq(HeroUserLabelAuthRecord::getLabelType, labelType)
            .eq(HeroUserLabelAuthRecord::getOperateType, operateType);
        this.update(updateWrapper);
    }

    @Override
    public Map<Long, Map<Date, Integer>> queryAuthDateNum(List<Long> uids, Integer labelType, Integer operateType,
        Date createTimeStart) {
        Map<Long, Map<Date, Integer>> resultMap = new HashMap<>();
        List<AuthDateNumBO> authDateNums =
            getBaseMapper().groupAuthDateNum(uids, labelType, operateType, createTimeStart);
        if (CollectionUtils.isEmpty(authDateNums)) {
            return resultMap;
        }

        //根据uid分组
        Map<Long, List<AuthDateNumBO>> uidAuthDateNumMap =
            authDateNums.stream().collect(Collectors.groupingBy(AuthDateNumBO::getUid));
        uidAuthDateNumMap.forEach((uid, authDateNumList) -> {
            //按date分组
            Map<Date, Integer> dateNumMap = authDateNumList.stream()
                .collect(Collectors.toMap(AuthDateNumBO::getAuthDate, AuthDateNumBO::getAuthNum));
            resultMap.put(uid, dateNumMap);
        });

        return resultMap;
    }

    @Override
    public Map<Long, Integer> queryUidAuthNum(List<Long> uids, Integer labelType, Integer operateType,
        Date createTimeStart) {
        Map<Long, Integer> resultMap = new HashMap<>();
        List<AuthDateNumBO> uidAuthNums =
            getBaseMapper().countUidAuthNum(uids, labelType, operateType, createTimeStart);
        if (CollectionUtils.isEmpty(uidAuthNums)) {
            return resultMap;
        }

        //根据uid分组
        return uidAuthNums.stream()
            .filter(bo -> Objects.nonNull(bo.getUid()))
            .collect(Collectors.toMap(AuthDateNumBO::getUid, AuthDateNumBO::getAuthNum));
    }


    private HeroUserLabelAuthRecord buildEntity(CreateAuthRecordBO createAuthRecordBO) {
        HeroUserLabelAuthRecord entity = new HeroUserLabelAuthRecord();
        entity.setFromUid(createAuthRecordBO.getFromUid());
        entity.setToUid(createAuthRecordBO.getToUid());
        entity.setLabelType(createAuthRecordBO.getLabelType());
        List<Long> labelIds = createAuthRecordBO.getLabelIds();
        entity.setLabelIds(StringUtil.list2Str(labelIds.stream().map(String::valueOf).collect(Collectors.toList())));
        entity.setOperateType(createAuthRecordBO.getOperateType());
        entity.setCancelReason(createAuthRecordBO.getCancelReason());
        entity.setCancelPics(StringUtil.list2Str(createAuthRecordBO.getCancelPics()));
        entity.setState(StateEnum.EFFECTIVE.getCode());
        entity.setCreateBy(createAuthRecordBO.getFromUid());
        entity.setUpdateBy(createAuthRecordBO.getFromUid());

        return entity;
    }
}